/**
 * Copyright (c) 2022 az13js
 * new_program & new_program_server is licensed under Mulan PSL v2.
 * You can use this software according to the terms and conditions of
 * the Mulan PSL v2.
 * You may obtain a copy of Mulan PSL v2 at:
 *          http://license.coscl.org.cn/MulanPSL2
 * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF
 * ANY KIND,EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO
 * NON-INFRINGEMENT, MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE.
 * See the Mulan PSL v2 for more details.
 *
 * 这是一个本地的用来执行用户输入命令的客户端，需要结合服务端用。
 *
 * 编译：
 *
 * g++ -o new_program new_program.cpp
 *
 * 执行：
 *
 * ./new_program 命令
 *
 * 或者：
 *
 * ./new_program "命令"
 * ./new_program '命令'
 *
 * 例如：
 *
 * ./new_program ls -lh
 * ./new_program free
 *
 * 当有 > 之类的特殊符号时，可以使用引号处理：
 *
 * ./new_program 'ls -lh >/dev/null'
 *
 * 说明：
 *
 * 服务器会通过本地 /tmp/new_program_server.sock （可用环境变量 NEW_PROGRAM_SOCKET_FILE 指定）
 * 发送给服务器。发送的命令是你传递给 new_program 的所有参数。
 *
 */
#include <sys/types.h>
#include <sys/socket.h>
#include <sys/un.h>
#include <unistd.h>

#include <iostream>

int main(int argc, char **argv) {
    using namespace std;
    sockaddr_un socketAddress;
    string socketFile("/tmp/new_program_server.sock"); // 这里路径长度不能大于107字节

    auto envSocketFile = getenv("NEW_PROGRAM_SOCKET_FILE");
    if (nullptr != envSocketFile) {
        if (string(envSocketFile).length() > 107 || string(envSocketFile).empty()) {
            cout << "NEW_PROGRAM_SOCKET_FILE.length() > 107 or empty, use default" << endl;
        } else {
            socketFile.assign(envSocketFile);
        }
    }

    cout << "Unix socket: " << socketFile << endl;

    string sendCommand; // 发送给 服务器端的执行命令

    for (int i = 1; i < argc; i++) {
        sendCommand += string(argv[i]);
        sendCommand += " "; // 添加额外的空格，保持命令传递后一致
    }
    cout << "Command is:" << endl;
    cout << sendCommand << endl;

    auto socketId = socket(AF_UNIX, SOCK_STREAM, 0);
    if (-1 == socketId) {
        cout << "Call socket fail, function return " << socketId << endl;
        return 1;
    }

    socketAddress.sun_family = AF_UNIX;
    socketAddress.sun_path[socketFile.length()] = '\0';
    socketFile.copy(socketAddress.sun_path, socketFile.length());

    if (0 != connect(socketId, (sockaddr *)&socketAddress, sizeof(socketAddress))) {
        cout << "Call connect fail" << endl;
        return 1;
    }

    // 将命令发送给服务器端，让服务器端处理并执行
    auto sendDataLength = send(socketId, sendCommand.c_str(), sendCommand.length(), 0);
    if (sendCommand.length() != sendDataLength) {
        cout << "Error, data not sent completely" << endl;
        close(socketId);
        return 1;
    }

    close(socketId);
    return 0;
}

